package com.thermal.thermal_inspection.filter;

import com.thermal.thermal_inspection.model.ResultCode;
import com.thermal.thermal_inspection.properties.IgnoreWhiteProperties;
import com.thermal.thermal_inspection.util.JWTUtil;
import com.thermal.thermal_inspection.util.RedisUtil;
import com.thermal.thermal_inspection.util.ResponseUtil;
import feign.Response;
import io.jsonwebtoken.Claims;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 全局网关鉴权 + 访问日志记录过滤器
 */
@Component
public class AuthFilter implements GlobalFilter, Ordered {

    private static final Logger log = LogManager.getLogger(AuthFilter.class);
    private static final String BEGIN_VISIT_TIME = "begin_visit_time";
    @Autowired
    private JWTUtil jwtUtil;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private IgnoreWhiteProperties ignoreWhiteProperties;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("进入全局处理器");
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();



        String uri = request.getURI().toString();
        String method = request.getMethod().toString();
        log.debug(">>> 开始处理请求: {} {}", method, uri);

        //验证是否存在白名单里面
        if (isWhiteListed(uri)) {
            log.debug("该请求是白名单请求，无需验证Token");
        }else {
            //获取并校验 token
            String token = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
            if (token == null || !isValidToken(token)) {
                log.warn("无效的访问令牌: {}", token);
                return ResponseUtil.webFluxResponseWriter(response, "application/json", HttpStatus.UNAUTHORIZED, "无效Token", ResultCode.UNAUTHORIZED);
            }
        }

        try {
            // 记录开始访问时间
            exchange.getAttributes().put(BEGIN_VISIT_TIME, System.currentTimeMillis());

            // 通过鉴权，继续处理请求
            return chain.filter(exchange)
                    .doOnSuccess(v -> log.debug("<<< 请求处理完成: {}", uri))
                    .doOnError(e -> log.error("!!! 请求处理异常: {}", e.getMessage(), e))
                    .then(Mono.fromRunnable(() -> logRequestInfo(exchange)));

        } catch (Exception e) {
            log.error("网关鉴权失败: URI={}, Error={}", uri, e.getMessage(), e);
            return ResponseUtil.webFluxResponseWriter(response, "application/json", HttpStatus.INTERNAL_SERVER_ERROR, "网关异常", ResultCode.SYSTEM_ERROR);
        }
    }

    // 检查URI是否在白名单中
    private boolean isWhiteListed(String uri) {
        System.out.println(uri);
        List<String> whiteUrls = ignoreWhiteProperties.getWhites();
        for (String whiteUrl : whiteUrls) {
            System.out.println(whiteUrl);
            if (uri.contains(whiteUrl)) {
                return true; // 如果URI包含白名单中的路径，放行
            }
        }
        return false; // 不在白名单中，进行Token验证
    }

    private boolean isValidToken(String token) {
        //令牌为空
        if (token.isEmpty())
            return false;
        Claims claims =jwtUtil.getClaimsFromToken(token);
        //令牌解析失败
        if (claims == null)
            return false;
        //令牌是否过期
        String userKey = jwtUtil.getTempUserIdFromToken(token);
        if (!redisUtil.exists(userKey))
            return false;
        String username = jwtUtil.getUsernameFromToken(token);
        if (username.isEmpty())
            return false;
        return true;
    }

    /**
     * 请求访问日志记录
     */
    private void logRequestInfo(ServerWebExchange exchange) {
        try {
            Long beginTime = exchange.getAttribute(BEGIN_VISIT_TIME);
            if (beginTime != null) {
                ServerHttpRequest request = exchange.getRequest();
                URI uri = request.getURI();

                Map<String, Object> logData = new LinkedHashMap<>();
                logData.put("method", request.getMethod().toString());
                logData.put("host", uri.getHost());
                logData.put("port", uri.getPort());
                logData.put("path", uri.getPath());
                logData.put("query", uri.getRawQuery());
                logData.put("duration", (System.currentTimeMillis() - beginTime) + " ms");

                log.info("访问接口信息: {}", logData);
                log.info("═════════════ 接口访问日志结束 ═════════════");
            }
        } catch (Exception e) {
            log.error("记录访问日志时发生异常: ", e);
        }
    }

    @Override
    public int getOrder() {
        return -200; // 越小越优先
    }
}
